import 'dart:async';
import 'dart:io';

import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'package:path_provider/path_provider.dart';
import 'package:sciolto/POJO/Song.dart';
import 'package:sciolto/POJO/SongList.dart';
import 'package:sciolto/util/DBController.dart';
import 'package:sciolto/util/setting.dart';

enum PlayerState { stopped, playing, paused }

enum PlayerType { common, listCycle, singleCycle, random }

enum CreateSonglistState{ success, duplication, error }

enum operationState{ success, error, specialError }

// TODO: 完善当应用退出时要回收资源
///
/// Music FileController SongsList都为静态资源
///
/// Music 负责播放音乐
/// FileController 负责获取文件夹中的信息并进行初步的处理
/// SongsList 负责获取SharedPreferences中的数据
///
/// （如果哪里出了问题，尝试着改一下逻辑，如果还是不行的话和我说
/// （我也是第一次设计这个模块））
/// 注意，所有的数据都在静态成员[_instance]中，我已经把 get 6-写好了，
/// 大概没什么问题，注意一下就好
///
class Music with ChangeNotifier {
  ///
  /// 构造方法
  ///
  factory Music() => _getInstance();

  get duration => _duration; // 总长度

  get position => _position; // 当前长度

  get playerState => _playerState; // 播放状态

  get audioPlayer => _audioPlayer; // 获取audioPlayer

  /// 获取歌曲实体类
  Song get song => _song;

  double get value => (position != null && // 获取播放进度条value
          duration != null &&
          position.inMilliseconds > 0 &&
          position.inMilliseconds < duration.inMilliseconds)
      ? position.inMilliseconds / duration.inMilliseconds
      : 0.0;

  String get showText => position != null // 获取进度文字显示
      ? '${_positionText ?? ''} / ${_durationText ?? ''}'
      : _duration != null
          ? '--/$_durationText'
          : '--/--';

  bool isLoaded;

  ///
  /// 从当前position开始播放音乐
  /// 如果当前播放的状态：
  ///   position不为null，
  ///   duration不为null，
  ///   播放时间正常————位置 > 0
  ///   播放时间小于总时间
  /// 则正常播放
  ///
  /// 播放歌曲需要设置当前歌名（并非在本方法中实现）
  ///
  Future<int> play() => _checkSongValidateThenInvoke(_play);

  ///
  /// 暂停
  ///
  Future<int> pause() => _checkSongValidateThenInvoke(_pause);

  ///
  /// 停止
  ///
  Future<int> stop() => _checkSongValidateThenInvoke(_stop);

  ///
  /// 当进度条变化时调用该函数
  ///
  void onChangeSlider(v) => _onChangeSlider(v);

  ///
  /// 释放资源
  ///
  void disposeAudio() => _dispose();

  ///
  /// 初始化所有资源
  ///
  Future<int> initAllResource() => _initAllResource();
  
  ///
  /// 检查歌曲是否有效
  /// 
  Future<int> _checkSongValidateThenInvoke(Function func) {
    if (song.id >= 0) {
      func();
    }return Future.delayed(Duration.zero, () => -1);
  }
  
  ///
  /// 播放情况获取
  ///
  bool get isPlaying => playerState == PlayerState.playing; // 是否在播放
  bool get isPaused => playerState == PlayerState.paused; // 是否暂停
  /// --------------------------------------------------------------------------
  ///
  /// 以下是私有方法区
  ///
  /// --------------------------------------------------------------------------

  // 播放歌曲实体类
  Song _song;

  // 播放模式（默认就行，面向游戏的背景音乐才需要改）
  PlayerMode mode;

  get audioPlayerState => _audioPlayerState;

  get durationSubscription => _durationSubscription;

  get positionSubscription => _positionSubscription;

  get playerCompleteSubscription => _playerCompleteSubscription;

  get playerErrorSubscription => _playerErrorSubscription;

  get playerStateSubscription => _playerStateSubscription;

  // 核心成员，音乐播放的控制中心
  AudioPlayer _audioPlayer;

  // 当前播放状态，枚举类型
  AudioPlayerState _audioPlayerState;

  // 音乐的总长度
  Duration _duration;

  // 音乐的当前位置
  Duration _position;

  // 播放状态，枚举类型
  PlayerState _playerState = PlayerState.stopped;

  // 监听音乐总长度的监听器
  // ignore: cancel_subscriptions
  StreamSubscription _durationSubscription;

  // 监听音乐当前长度的监听器
  // ignore: cancel_subscriptions
  StreamSubscription _positionSubscription;

  // 监听音乐播放是否结束的监听器
  // ignore: cancel_subscriptions
  StreamSubscription _playerCompleteSubscription;

  // 监听音乐播放错误的监听器
  // ignore: cancel_subscriptions
  StreamSubscription _playerErrorSubscription;

  // 监听音乐播放状态的监听器
  // ignore: cancel_subscriptions
  StreamSubscription _playerStateSubscription;

  // 播放总长度文字显示
  String get _durationText => duration?.toString()?.split('.')?.first ?? '';

  // 播放当前长度文字显示
  String get _positionText => position?.toString()?.split('.')?.first ?? '';

  ///
  /// 静态单例成员[_instance]初始化方法集
  ///
  static Music _instance;

  static Music _getInstance() => _instance ??= new Music._internal();

  Music._internal() {
    // 私有构造器
    print('get Music');

    // Music(){
    _audioPlayer = AudioPlayer();

    _durationSubscription = _audioPlayer.onDurationChanged.listen((duration) {
      _duration = duration;
      notifyListeners();
    });

    _positionSubscription =
        _audioPlayer.onAudioPositionChanged.listen((position) {
      _position = position;
      notifyListeners();
    });

    _playerCompleteSubscription =
        _audioPlayer.onPlayerCompletion.listen((event) {
      print("song has completed");
      _position = _duration;
      _onComplete();
      notifyListeners();
    });

    _playerErrorSubscription = _audioPlayer.onPlayerError.listen((msg) {
      print("audioPlayer error : $msg");
      _playerState = PlayerState.stopped;
      _duration = Duration(seconds: 0);
      _position = Duration(seconds: 0);
      notifyListeners();
    });

    _audioPlayer.onPlayerStateChanged.listen((state) {
      print("song's state changed");
      try {
        _audioPlayerState = state;
        notifyListeners();
      } catch (e) {
        return;
      }
    });

    _audioPlayer.onNotificationPlayerStateChanged.listen((state) {
      try {
        _audioPlayerState = state;
        notifyListeners();
      } catch (e) {
        return;
      }
    });
  }

  Future<int> _play() async {
    final playPosition = (position != null &&
            duration != null &&
            position.inMilliseconds > 0 &&
            position.inMilliseconds < duration.inMilliseconds)
        ? position
        : null;

    if (FileController()._url != null) {
      final result = await audioPlayer.play(
          "${FileController().url}/${_song.mp3FileName}",
          isLocal: true,
          position: playPosition);
      if (result == 1) {
        _playerState = PlayerState.playing;
        notifyListeners();
      }
      audioPlayer.setPlaybackRate(playbackRate: 1.0);
      return result;
    }

    return 0;
  }

  Future<int> _pause() async {
    final result = await audioPlayer.pause();
    if (result == 1) {
      _playerState = PlayerState.paused;
      notifyListeners();
    }
    return result;
  }

  Future<int> _stop() async {
    final result = await audioPlayer.stop();
    if (result == 1) {
      _playerState = PlayerState.stopped;
      _position = Duration();
      audioPlayer.seek(Duration(milliseconds: 0));
      notifyListeners();
    }
    return result;
  }

  void _onComplete() {
    _playerState = PlayerState.stopped;
    PlayList().setNextSongShouldPlay();
  }

  void _onChangeSlider(v) {
    double position = v * duration.inMilliseconds;
    audioPlayer.seek(Duration(milliseconds: position.round()));
    notifyListeners();
  }

  void _setPlayingSong(Song song) {
    _song = song;
    print('$_song');
    notifyListeners();
  }

  void _dispose() {
    _audioPlayer.stop();
    _durationSubscription?.cancel();
    _positionSubscription?.cancel();
    _playerCompleteSubscription?.cancel();
    _playerErrorSubscription?.cancel();
    _playerStateSubscription?.cancel();
  }

  Future<int> _initAllResource() async{
    int result = 0;
    result += await FileController()._loadLocalDirectory();
    print('''
    
    -----------------------------------------------
    文件加载控制器初始化完毕
    -----------------------------------------------
    ''');
    result += await SongsInfo()._checkAllSongWhetherExistedAndValid();
    print('''
    
    -----------------------------------------------
    音乐信息加载完毕
    -----------------------------------------------
    ''');
    result += await PlayList()._init();
    print('''
    
    -----------------------------------------------
    播放列表初始化完毕
    -----------------------------------------------
    ''');
    if (PlayList().listOfSong.isNotEmpty) {
      Music()._setPlayingSong(PlayList().listOfSong[0]);
      Music().isLoaded = true;
    }else{
      Music()._setPlayingSong(Song("unknown - 无歌曲.mp3"));
      Music().isLoaded = false;
    }
    return result;
  }
}

///
/// 与文件系统交互的类
/// api：
///   [FileController()] 构造方法，创建或获取静态实例
///   [url] 文件路径的getter方法
///   [getFileNameList] 获取文件夹下的文件名列表
///
class FileController with ChangeNotifier {
  ///
  /// 构造方法
  ///
  factory FileController() => _getInstance();

  ///
  /// app外部可见文件夹路径
  ///
  get url => _url ?? '';

  ///
  /// 获取歌曲名列表
  ///
  /// 并没有直接获取文件夹下所有文件名的方法，但是可以获得实体Entity
  /// 每个实体有其对应的路径
  /// 本方法的思想就是获取路径，然后将其与[_url]相减，剩下的就是文件名了
  ///
  /// 以验证可行
  ///
  /// 注意，一般不通过该方法获取全部歌曲，
  /// 而是使用[SongsInfo]的[findSongsWithSongsList]
  ///
  List<String> getFileNameList() => _getMusicNameList();

  /// --------------------------------------------------------------------------
  ///
  /// 以下是私有方法区
  ///
  /// --------------------------------------------------------------------------

  // 静态单例成员
  static FileController _fileController;

  static FileController _getInstance() {
    //print('get FileController');
    return _fileController ??= new FileController._internal();
  }

  FileController._internal();

  String _url;
  Directory _appStoreDir;

  ///
  /// 获取APP外部文件夹
  /// 在第一次初始化[_fileController]的时候就调用，获取到app外部存储文件夹
  ///
  Future<int> _loadLocalDirectory() async {
    _appStoreDir = await getExternalStorageDirectory();
    _url = _appStoreDir.path;
    print('外部存储目录 : $url');
    _getMusicNameList();
    return 1;
  }

  List<String> _getMusicNameList() {
    // ignore: non_constant_identifier_names
    var EntityList = _appStoreDir?.listSync();
    List<String> result = [];
    EntityList.forEach((element) {
      // +1 是为了去除'/'
      result.add(element.path.substring(_url.length + 1));
    });
    if (result.isEmpty)
      print('文件夹下为空');
    return result;
  }
}

///
/// SongsInfo 用来存储：
///   歌单信息
///   每个歌属于哪个歌单
///
/// api：
///   [SongsInfo()] 创建或获取静态实例
///   [addSongIntoPrefs] 将歌曲加入到SharedPreference中
///   [createNewSongList] 创建一个新的歌单
///   [checkAllSongWhetherExisted] 查看文件夹下所有的歌曲是否已经在prefs中，并且去除所有非mp3文件
///   [findSongsWithSongsList] 通过歌单名称获取歌曲
///   [getSongLists] 获取歌单列表
///
class SongsInfo with ChangeNotifier {
  ///
  /// 构造方法
  ///
  factory SongsInfo() => _getInstance();

  ///
  /// 添加歌曲进入 数据库
  /// 每次登陆时应该检测文件夹下是否有新增加的歌曲，如果有则添加进 数据库
  /// 这里是添加的方法
  ///
  void addSongIntoPrefs(Song song) => _addSongIntoPrefs(song);

  ///
  /// 成功返回true,失败返回false,一般是已经有相同名称的歌单
  ///
  Future<CreateSonglistState> createNewSongList(SongList songList) =>
      _createNewSongList(songList);

  ///
  /// 检查是否文件夹下的每一个歌曲都在 数据库 中
  ///
  Future<int> checkAllSongWhetherExisted() => _checkAllSongWhetherExistedAndValid();

  ///
  /// 根据歌单名获取歌曲列表
  ///
  Future<List<Song>> findSongsWithSongsList(SongList list) =>
      _findSongsWithSongsList(list);

  ///
  /// 获取歌单列表
  ///
  Future<List<SongList>> getSongLists() => _getSongLists();

  ///
  /// 更新歌单点击数
  ///
  Future<int> clickSonglist(SongList songList) => _clickSonglist(songList);

  ///
  /// 删除歌单操作
  ///
  Future<CreateSonglistState> deleteSonglist(SongList songList) => _deleteSonglist(songList);

  ///
  /// 从歌单中删除歌曲
  ///
  Future<int> deleteSongFromSonglist(SongList songList, Song song) => _deleteSongFromSonglist(songList, song);

  ///
  /// 添加歌曲进入歌单
  ///
  Future<int> addSongIntoSonglist(SongList songList, Song song) => _addSongIntoSonglist(songList, song);

  ///
  /// 更新歌单信息
  ///
  Future<SongList> updateSonglist(SongList songList, String where, List<dynamic> whereArgs) => _updateSonglist(songList, where, whereArgs);

  /// --------------------------------------------------------------------------
  ///
  /// 以下是私有方法区
  ///
  /// --------------------------------------------------------------------------

  static SongsInfo _info;

  static SongsInfo _getInstance() => _info ??= new SongsInfo._internal();

  SongsInfo._internal();

  List<dynamic> _songlistNameList;

  void _addSongIntoPrefs(Song song) async {
    TableConnector connector = TableConnectorFactory.connectWithSongTable();
    var list = await connector.defaultQueryAll();
    if (list.contains(song))
      await connector.defaultInsert(song.toMap());
  }

  Future<List<SongList>> _getSongLists() async{
    TableConnector connector = TableConnectorFactory.connectWithSonglistTable();
    var result = await connector.defaultQueryAll();
    print('以获取到所有的歌单，detail = $result');
    List<SongList> songListList = result.isNotEmpty
        ? result.map((e) => SongList.fromMap(e)).toList() : [];
    return songListList;
  }

  Future<CreateSonglistState> _createNewSongList(SongList songList) async {
    if(_songlistNameList.contains(songList.listName)) return CreateSonglistState.duplication;
    try{
      TableConnector connector = TableConnectorFactory.connectWithSonglistTable();
      await connector.defaultInsert(songList.toMap());
      await _updateState();
      print('songlist = $_songlistNameList');
      return CreateSonglistState.success;
    }catch(e){
      return CreateSonglistState.error;
    }
  }

  Future<SongList> _updateSonglist(SongList songList, String where, List<dynamic> whereArgs) async {
    TableConnector con = TableConnectorFactory.connectWithSonglistTable();
    int id = songList.id;
    await con.defaultUpdate(songList.toMap(), where, whereArgs);
    await _updateState();
    List<SongList> list = await _getSongLists();
    for(SongList item in list)
      if(item.id == id) return item;
    return null;
  }

  Future<int> _addSongIntoSonglist(SongList songList, Song song) async {
    TableConnector connector = TableConnectorFactory.connectWithBelongingTable();
    return await connector.customInsert(lid: songList.id, sid: song.id);
  }

  Future<CreateSonglistState> _deleteSonglist(SongList songList) async {
    try{
      if(songList.id == 1 || songList.listName == '全部歌曲')
        return CreateSonglistState.duplication;
      TableConnector connector = TableConnectorFactory.connectWithSonglistTable();
      connector.defaultDelete("id = ?", [songList.id]);
      connector = TableConnectorFactory.connectWithBelongingTable();
      connector.defaultDelete('lid = ?', [songList.id]);
      _updateState();
      return CreateSonglistState.success;
    }catch(e){
      return CreateSonglistState.error;
    }
  }

  Future<int> _deleteSongFromSonglist(SongList songList, Song song) async {
    TableConnector connector = TableConnectorFactory.connectWithBelongingTable();
    return await connector.defaultDelete("lid = ? and sid = ?", [songList.id, song.id]);
  }

  Future<int> _checkAllSongWhetherExistedAndValid() async{
    TableConnector connector = TableConnectorFactory.connectWithSongTable();
    List nameListInFile = FileController().getFileNameList() ?? [];
    List<Map<String, dynamic>> list = await connector.defaultQueryAll();
    List<Song> songListInDB = list.isNotEmpty
        ? list.map((e) => Song.fromMap(e)).toList() : [];
    List<String> songNameListInDB = list.isNotEmpty
        ? songListInDB.map((e) => e.mp3FileName).toList() : [];
    print('获取到数据库中的歌曲 , list = $songListInDB');
    for (String name in nameListInFile) {
      if (!songNameListInDB.contains(name)) {
        if (name.split('-')[1].split('.')[1] == "mp3") {
          await connector.defaultInsert(Song(name).toMap());
          print('已向数据库中插入 $name');
        }
      }
    }
    for(Song song in songListInDB){
      if (!nameListInFile.contains(song.mp3FileName)) {
        int count = await connector.defaultDelete("id = ?", [song.id]);
        print('-----has removed $song, 移除了$count个-----');
      }
    }
    connector = TableConnectorFactory.connectWithSonglistTable();
    var result = await connector.defaultQueryAll();
    _songlistNameList = result.isNotEmpty
        ? result.map((e) => e['list_name']).toList() : [];
    if (!_songlistNameList.contains("全部歌曲")) {
      await connector.defaultInsert(SongList("全部歌曲", "images/list_0.jpg", ImageResourceType.ASSET, "").toMap());
    }
    return 1;
  }

  Future _updateState() async {
    TableConnector connector = TableConnectorFactory.connectWithSonglistTable();
    var result = await connector.defaultQueryAll();
    _songlistNameList = result.isNotEmpty
        ? result.map((e) => e['list_name']).toList() : [];
  }

  Future<List<Song>> _findSongsWithSongsList(SongList songList) async {
    List<Map<String, dynamic>> list;
    if(songList.listName == '全部歌曲'){
      TableConnector connector = TableConnectorFactory.connectWithSongTable();
      list = await connector.defaultQueryAll();
    }else{
      TableConnector connector = TableConnectorFactory.connectWithSonglistTable();
      list = await connector.customQuery(songList);
    }
    return list.isNotEmpty ?
        list.map((e) => Song.fromMap(e)).toSet().toList() : [];
  }

  Future<int> _clickSonglist(SongList songList) async {
    songList.hits ++;
    TableConnector connector = TableConnectorFactory.connectWithSonglistTable();
    await connector.defaultUpdate(songList.toMap(), 'id = ?', [songList.id]);
    await _updateState();
    return 1;
  }
}

///
/// 播放列表类
///
/// // TODO:播放列表类完全管理歌曲的播放，一切播放行为都归结到播放列表类的手上
///
/// 播放列表需要实现的事件包括：
/// api:
///   [setCurrentPlayList] 设置播放列表并从新播放列表的第一个歌曲开始播放 √
///   [currentType] 设置播放列表播放的类型包括[PlayerType.common],[PlayerType.listCycle],[PlayerType.singleCycle] √
///   [deleteSongFromListWithIndex] 从播放列表中删除某一个歌曲 √
///   [listOfSong] 获取播放列表中的歌曲列表 √
///   [setNextSongShouldPlay] 获取下一首应当播放的歌 √
///
///   。。。
///
/// 刚打开应用时，默认的播放列表是“全部歌曲”歌单
/// 注意，这里和原来设计的设置最近一次播放歌曲冲突，考虑以后放弃原来的获取最近一次播放歌曲的功能
///

class PlayList {
  factory PlayList() => _getInstance();

  ///
  /// 获取播放歌曲列表
  ///
  List<Song> get listOfSong => _listOfSong;

  ///
  /// 获取当前装载的歌单
  ///
  SongList get currentSongList => _currentSonglist;

  ///
  /// 获取当前列表播放状态
  ///
  PlayerType get currentType => _currentType;

  ///
  /// 改变列表播放状态
  ///
  set currentType(type) => _currentType = type;

  ///
  /// 获取当前播放位置
  ///
  int get currentSongIndex => _currentSongIndex;

  ///
  /// 根据索引从播放列表中删除歌曲
  ///
  List<Song> deleteSongFromListWithIndex(int index) =>
      _deleteSongFromListWithIndex(index);

  ///
  /// 设置下一首播放的歌
  ///
  void setNextSongShouldPlay() => _setNextSongShouldPlay();

  ///
  /// 设置上一首播放的歌
  ///
  void setPreviousShouldPlay() => _setPreviousSongShouldPlay();

  ///
  /// 设置当前播放列表，并从第一首开始播放
  ///
  void setCurrentPlayList(List<Song> newList, SongList sList) => _setCurrentPlayList(newList, sList);

  ///
  /// 点击一个歌曲后，设置播放歌曲
  ///
  Future<int> selectMusic(int index, SongList sList) => _selectMusic(index, sList);

  ///
  /// 移动歌曲
  ///
  void moveMusic(int oldIndex, int newIndex) => _moveMusic(oldIndex, newIndex);

  ///
  /// 设置歌曲下一首播放
  ///
  void insertSongBehind(Song song) => _insertSongBehind(song);

  /// --------------------------------------------------------------------------
  ///
  /// 以下是私有区
  ///
  /// --------------------------------------------------------------------------
  static PlayList _instance;
  List<Song> _listOfSong;
  SongList _currentSonglist;
  PlayerType _currentType;
  int _currentSongIndex;

  static _getInstance() => _instance ??= new PlayList._internal();

  PlayList._internal();

  Future<int> _init() async {
    _listOfSong = await SongsInfo().findSongsWithSongsList(SongList("全部歌曲", null, null, null));
    TableConnector connector = TableConnectorFactory.connectWithSonglistTable();
    var list = await connector.defaultQuery("list_name = ?", ["全部歌曲"]);
    assert(list.isNotEmpty);
    _currentSonglist = SongList.fromMap(list.first);
    print('播放列表为:$_currentSonglist');
    _currentType = PlayerType.common;
    _currentSongIndex = 0;
    return 1;
  }

  List<Song> _deleteSongFromListWithIndex(int index) {
    assert(index < _listOfSong.length && index >= 0, "dyy : index out of range!");
    if(index == currentSongIndex){
      _setNextSongShouldPlay();
    }
    if(index < currentSongIndex){
      _currentSongIndex --;
    }
    return _listOfSong..removeAt(index);
  }

  void _insertSongBehind(Song song) {
    if(song == Music().song) return;
    if(!_listOfSong.contains(song)){
      _listOfSong.insert(_currentSongIndex + 1, song);
    }else{
      int index = _listOfSong.indexOf(song);
      _listOfSong.removeAt(index);
      _listOfSong.insert(_currentSongIndex + 1, song);
    }
  }


  void _setCurrentPlayList(List<Song> newList, SongList sList) {
    assert(newList != null);
    _listOfSong = newList;
    _currentSonglist = sList;
    _currentSongIndex = 0;
    Music()._setPlayingSong(_listOfSong[_currentSongIndex]);
    Music().stop();
    Music().play();
  }

  void _setPreviousSongShouldPlay() {
    switch (_currentType) {
      case PlayerType.common:
        if (_currentSongIndex == 0) {
          _currentSongIndex = 0;
          Music()
            ..stop()
            .._setPlayingSong(listOfSong[_currentSongIndex]);
        } else {
          Music()
            ..stop()
            .._setPlayingSong(listOfSong[--_currentSongIndex])
            ..play();
        }
        break;
      case PlayerType.listCycle:
        Music()
          ..stop()
          .._setPlayingSong(
              listOfSong[(--_currentSongIndex) % listOfSong.length])
          ..play();
        break;
      case PlayerType.singleCycle:
        Music()
          ..stop()
          ..play();
        break;
      case PlayerType.random:
        int nextIndex =
            _listOfSong[_currentSongIndex].mp3FileName.length % _listOfSong.length;
        nextIndex += nextIndex == _currentSongIndex ? 1 : 0;
        _currentSongIndex = nextIndex % listOfSong.length;
        Music()
          ..stop()
          .._setPlayingSong(
              listOfSong[_currentSongIndex])
          ..play();
    }
    _currentSongIndex %= listOfSong.length;
  }

  void _setNextSongShouldPlay() {
    switch (_currentType) {
      case PlayerType.common:
        if (_currentSongIndex == _listOfSong.length - 1) {
          _currentSongIndex = 0;
          Music()
            ..stop()
            .._setPlayingSong(listOfSong[_currentSongIndex]);
        } else {
          Music()
            ..stop()
            .._setPlayingSong(listOfSong[++_currentSongIndex])
            ..play();
        }
        break;
      case PlayerType.listCycle:
        Music()
          ..stop()
          .._setPlayingSong(
              listOfSong[(++_currentSongIndex) % listOfSong.length])
          ..play();
        break;
      case PlayerType.singleCycle:
        Music()
          ..stop()
          ..play();
        break;
      case PlayerType.random:
        int nextIndex =
            _listOfSong[_currentSongIndex].mp3FileName.length % _listOfSong.length;
        nextIndex += nextIndex == _currentSongIndex ? 1 : 0;
        _currentSongIndex = nextIndex % listOfSong.length;
        Music()
          ..stop()
          .._setPlayingSong(
              listOfSong[_currentSongIndex])
          ..play();
    }
    _currentSongIndex %= listOfSong.length;
  }

  Future<int> _selectMusic(int index, SongList sList) async {
    if(sList != currentSongList){
      _listOfSong = await SongsInfo()._findSongsWithSongsList(sList);
      _currentSongIndex = index;
      Music()._setPlayingSong(_listOfSong[_currentSongIndex]);
      Music().stop();
      Music().play();
      return 0;
    }else{
      _currentSongIndex = index;
      Music()._setPlayingSong(_listOfSong[_currentSongIndex]);
      Music().stop();
      Music().play();
      return 1;
    }
  }

  void _moveMusic(int oldIndex, int newIndex){
    if(oldIndex < newIndex) newIndex -= 1;
    Song item = _listOfSong.removeAt(oldIndex);
    _listOfSong.insert(newIndex, item);
    if(currentSongIndex == oldIndex) _currentSongIndex = newIndex;
    else if(currentSongIndex > oldIndex && currentSongIndex <= newIndex)
      _currentSongIndex --;
    else if(currentSongIndex < oldIndex && currentSongIndex >= newIndex)
      _currentSongIndex ++;
  }
}
